package com.yingsheng.bi.hks.service.comm;

import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.google.gson.Gson;
import com.yingsheng.bi.hks.basic.enums.EnumConst;
import com.yingsheng.bi.hks.basic.exception.TencentRuntimeException;
import com.yingsheng.bi.hks.comm.WxPayMpCreateOrderReq;
import com.yingsheng.bi.hks.comm.WxPayMpCreateOrderRes;
import com.yingsheng.bi.hks.comm.WxPayMpQueryOrderReq;
import com.yingsheng.bi.hks.comm.WxPayMpQueryOrderRes;
import com.yingsheng.bi.hks.repository.dao.po.GoodsOrders;
import com.yingsheng.bi.hks.repository.dao.service.GoodsOrdersDaoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Map;
import java.util.TreeMap;

/**
 * 微信支付服务
 *
 * @author root
 */
@Slf4j
@Service
public class WxPayBiService {

    @Autowired
    private WxPayService wxPayService;

    @Autowired
    private GoodsOrdersDaoService goodsOrdersDaoService;

    @Value("${wx.pay.apiV3Key}")
    private String apiKey;

    public WxPayMpCreateOrderRes createOrder(WxPayMpCreateOrderReq req) {
        /*
         * 1.构建调用微信支付平台的接口参数
         */
        WxPayUnifiedOrderV3Request wxPayRequest = new WxPayUnifiedOrderV3Request();
        wxPayRequest.setDescription(req.getDescription());
        wxPayRequest.setOutTradeNo(req.getOrderNo());

        WxPayUnifiedOrderV3Request.Amount amount = new WxPayUnifiedOrderV3Request.Amount();
        amount.setCurrency(req.getCurrency());
        amount.setTotal(req.getAmount());
        wxPayRequest.setAmount(amount);
        WxPayUnifiedOrderV3Request.Payer payer = new WxPayUnifiedOrderV3Request.Payer();
        payer.setOpenid(req.getOpenid());
        wxPayRequest.setPayer(payer);

        /*
         * 2.处理微信支付平台的接口响应信息
         */
        WxPayMpCreateOrderRes res = new WxPayMpCreateOrderRes();
        try {
            WxPayUnifiedOrderV3Result.JsapiResult jsapiResult = wxPayService.createOrderV3(TradeTypeEnum.JSAPI, wxPayRequest);
            res.setTimeStamp(jsapiResult.getTimeStamp());
            res.setNonceStr(jsapiResult.getNonceStr());
            res.setPackageValue(jsapiResult.getPackageValue());
            res.setSignType(jsapiResult.getSignType());
            res.setPaySign(jsapiResult.getPaySign());
        } catch (WxPayException e) {
            log.error(e.getMessage(), e);
            throw new TencentRuntimeException(e.getErrCode(), e.getErrCodeDes());
        }
        return res;
    }

    public WxPayMpQueryOrderRes queryOrder(WxPayMpQueryOrderReq req) {
        WxPayMpQueryOrderRes res = new WxPayMpQueryOrderRes();
        try {
            WxPayOrderQueryV3Result wxQueryRes = wxPayService.queryOrderV3(null, req.getOrderNo());
            res.setAppid(wxQueryRes.getAppid());
            res.setMchid(wxQueryRes.getMchid());
            if (!ObjectUtils.isEmpty(wxQueryRes.getPayer())) {
                res.setOpenid(wxQueryRes.getPayer().getOpenid());
            }
            res.setWxOrderNo(wxQueryRes.getTransactionId());
            res.setWxOrderState(wxQueryRes.getTradeState());
            res.setWxOrderStateDesc(wxQueryRes.getTradeStateDesc());
            res.setWxOrderPayTime(wxQueryRes.getSuccessTime());
        } catch (WxPayException e) {
            log.error(e.getMessage(), e);
            throw new TencentRuntimeException(e.getErrCode(), e.getErrCodeDes());
        }
        return res;
    }

    public String mqOrderNotice(HttpServletRequest request) {
        try {
            // 1. 读取微信通知的 XML 数据
            String xmlData = readRequestBody(request);
            log.info("mqOrderNotice:" + xmlData);

            // 2. 解析 XML 并验证签名
            Map<String, String> notifyData = parseXmlAndVerifySign(xmlData);

            // 3. 处理业务逻辑（如更新订单状态）
            boolean success = processBusiness(notifyData);

            // 4. 返回响应给微信服务器
            return success ?
                    "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>" :
                    "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[ERROR]]></return_msg></xml>";
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[ERROR]]></return_msg></xml>";
        }
    }

    // 读取请求体的 XML 数据
    private String readRequestBody(HttpServletRequest request) throws IOException {
        StringBuilder sb = new StringBuilder();
        try (BufferedReader reader = request.getReader()) {
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        }
        return sb.toString();
    }

    private Map<String, String> parseXmlAndVerifySign(String xmlData) throws Exception {
        // 解析 XML
        Gson gson = new Gson();
        Map<String, Object> dataMap = gson.fromJson(xmlData,Map.class);

        // 验证签名 todo
//        String signFromWechat = dataMap.get("sign");
//        String generatedSign = generateSignature(dataMap, apiKey); // 替换为你的 API 密钥
//        if (!signFromWechat.equals(generatedSign)) {
//            throw new ServiceRuntimeException("签名验证失败！");
//        }

        Map<String, String> resource =(Map)dataMap.get("resource");
        String  str = decryptToString(resource.get("associated_data").getBytes(StandardCharsets.UTF_8),
                resource.get("nonce").getBytes(StandardCharsets.UTF_8),resource.get("ciphertext"));
        Map<String, String> res =gson.fromJson(str,Map.class);

        return res;
    }

    private String generateSignature(Map<String, String> data, String apiKey) {
        // 1. 过滤空值并按字段名排序
        TreeMap<String, String> sortedParams = new TreeMap<>(data);
        sortedParams.entrySet().removeIf(entry -> entry.getValue() == null || entry.getKey().equals("sign"));

        // 2. 拼接成 URL 查询字符串
        StringBuilder sb = new StringBuilder();
        sortedParams.forEach((key, value) -> sb.append(key).append("=").append(value).append("&"));
        sb.append("key=").append(apiKey);

        // 3. MD5 加密并转为大写
        return DigestUtils.md5Hex(sb.toString()).toUpperCase();
    }

    private boolean processBusiness(Map<String, String> notifyData) {
        String outTradeNo = notifyData.get("out_trade_no");
        String resultCode = notifyData.get("trade_state");
        log.info("processBusiness:"+resultCode+"-"+outTradeNo);
        // 1. 根据 out_trade_no 查询订单
        GoodsOrders goodsOrders = goodsOrdersDaoService.queryOrderById(outTradeNo);
        if (goodsOrders == null) {
            return false;
        }

        // 2. 幂等性检查：如果订单已处理，直接返回成功
        if (EnumConst.GoodsOrderState.state_0.equals(goodsOrders.getOrderState())) {
            return true;
        }

        // 3. 更新订单状态
        if ("SUCCESS".equals(resultCode)) {
            goodsOrders.setOrderState(EnumConst.GoodsOrderState.state_0);
            return goodsOrdersDaoService.updateById(goodsOrders);
        } else {
            // 处理支付失败逻辑
            return false;
        }
    }

    public static String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext)
            throws GeneralSecurityException, IOException {

        try {
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            SecretKeySpec key = new SecretKeySpec("d7f10b2baad144f7bd09dc8e78683ef7".getBytes(),"AES");
            GCMParameterSpec spec = new GCMParameterSpec(128, nonce);
            cipher.init(Cipher.DECRYPT_MODE, key, spec);
            cipher.updateAAD(associatedData);
            return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new IllegalStateException(e);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
            throw new IllegalArgumentException(e);
        }
    }

}
